using System;
using System.Globalization;
using GammaJul.ReSharper.GammaXaml.Highlightings.CSharp;
using GammaJul.ReSharper.GammaXaml.Psi.Xaml;
using JetBrains.Annotations;
using JetBrains.Application.Progress;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Feature.Services.Bulbs;
using JetBrains.ReSharper.Intentions.Extensibility;
using JetBrains.ReSharper.Intentions.Util;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.TextControl;
using JetBrains.Util;

namespace GammaJul.ReSharper.GammaXaml.QuickFixes.CSharp {

	/// <summary>
	/// Quick fix that changes a CLR dependency property wrapper type.
	/// </summary>
	[QuickFix]
	public sealed class ChangeAccessorTypeFix : QuickFixBase {
		private readonly MismatchedDpAccessorTypeHighlighting _highlighting;

		public override string Text {
			get {
				return String.Format(
					CultureInfo.CurrentCulture,
					"Change type of '{0}' to '{1}'",
					_highlighting.Accessor.ShortName,
					_highlighting.DpRegisteredType.GetPresentableName(CSharpLanguage.Instance));
			}
		}
		
		protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress) {
			IType dpRegisteredType = _highlighting.DpRegisteredType;

			var property = _highlighting.Accessor as IProperty;
			if (property != null)
				ChangePropertyType(dpRegisteredType, property);

			else {
				var method = _highlighting.Accessor as IMethod;
				if (method != null)
					ChangeMethodType(dpRegisteredType, method);
			}

			return null;
		}

		private static void ChangePropertyType([NotNull] IType dpRegisteredType, [NotNull] IProperty property) {
			foreach (IPropertyDeclaration declaration in property.GetDeclarations())
				declaration.SetType(dpRegisteredType);
		}

		private static void ChangeMethodType([NotNull] IType dpRegisteredType, [NotNull] IMethod method) {
			if (method.ShortName.IsDpAttachedGetterName()) {
				foreach (IMethodDeclaration declaration in method.GetDeclarations())
					declaration.SetType(dpRegisteredType);
			}
			else if (method.ShortName.IsDpAttachedSetterName()) {
				foreach (IMethodDeclaration declaration in method.GetDeclarations())
					declaration.ParameterDeclarations[1].SetType(dpRegisteredType);
			}
		}

		public override bool IsAvailable(IUserDataHolder cache) {
			return _highlighting.IsValid()
				&& ValidUtils.Valid(_highlighting.Accessor, true);
		}

		public ChangeAccessorTypeFix([NotNull] MismatchedDpAccessorTypeHighlighting highlighting) {
			if (highlighting == null)
				throw new ArgumentNullException("highlighting");
			_highlighting = highlighting;
		}
	}

}
